package com.yiji.fintech.musfinance.common.factory.domain;

import com.acooly.core.common.facade.OrderBase;
import com.acooly.core.utils.mapper.BeanCopier;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.yiji.fintech.musfinance.base.enums.SubTransactionTypeEnum;
import com.yiji.fintech.musfinance.base.enums.TransactionTypeEnum;
import com.yiji.fintech.musfinance.common.annotation.Field2Filed;
import com.yiji.fintech.musfinance.common.domain.base.BaseDomain;
import com.yiji.fintech.musfinance.common.exception.AbortBizException;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.Set;

/**
 * Created by ouwen@yiji.com} on 2017/9/13.
 */
@Slf4j
public abstract class AbstractBaseFactory {

    /**Order和Domain对应关系*/
    protected static Map<Class,Class> ORDER2DOMAIN = Maps.newConcurrentMap();

    public BaseDomain doExcute(OrderBase orderBase){
        log.info("GID【{}}】流水号【{}】Order转换Domain前Order：【{}】",orderBase.getGid(),null,orderBase);
        BaseDomain domain = factory(orderBase);//注解获取Order和Domain关系
        BeanCopier.copy(orderBase, domain, BeanCopier.CopyStrategy.IGNORE_NULL, BeanCopier.NoMatchingRule.IGNORE,null);
        annotationToFiled(domain);//字段属性值转换
        converterType(domain);//交易标识转换子交易类型
        log.info("GID【{}}】外部流水号【{}】内部流水号【{}】Order转换Domain后Domain：【{}】",domain.getGid(),domain.getMerchOrderNo(),domain.getBizOrderNo(),domain);
        return domain;
    }
    private void converterType(BaseDomain domain){
        switch (domain.getTradeType()){
            case WITHDRAW://提现
                domain.setTransactionType(TransactionTypeEnum.WITHDRAW);
                domain.setSubTransactionType(SubTransactionTypeEnum.WITHDRAW);
                break;
            case DEDUCT_DEPOSIT://代扣
                domain.setTransactionType(TransactionTypeEnum.DEPOSIT);
                domain.setSubTransactionType(SubTransactionTypeEnum.DEDUCT);
                break;
            case SIGN://签约
                domain.setTransactionType(TransactionTypeEnum.SIGN);
                domain.setSubTransactionType(SubTransactionTypeEnum.DEFAULT);
                break;
            case NET_DEPOSIT://网银表单
                domain.setTransactionType(TransactionTypeEnum.DEPOSIT);
                domain.setSubTransactionType(SubTransactionTypeEnum.ONLINEBANK_FROM);
                break;
            case DEPOSIT_BACK://充值充退
                domain.setTransactionType(TransactionTypeEnum.DEPOSIT_BACK);
                domain.setSubTransactionType(SubTransactionTypeEnum.DEPOSIT_BACK);
                break;
            case NET_DEPOSIT_PAY_BACK://网银充退
                domain.setTransactionType(TransactionTypeEnum.DEPOSIT_BACK);
                domain.setSubTransactionType(SubTransactionTypeEnum.NET_DEPOSIT_PAY_BACK);
                break;
            case OFFLINE_PAY://线下充值
                domain.setTransactionType(TransactionTypeEnum.DEPOSIT);
                domain.setSubTransactionType(SubTransactionTypeEnum.OFFLINE_PAY);
                break;
            case WECHAT_PUBLIC_PAY://微信公众号
                domain.setTransactionType(TransactionTypeEnum.DEPOSIT);
                domain.setSubTransactionType(SubTransactionTypeEnum.WX_PUBLIC_PAY);
                break;
            case WECHAT_APP_PAY://微信APP
                domain.setTransactionType(TransactionTypeEnum.DEPOSIT);
                domain.setSubTransactionType(SubTransactionTypeEnum.WX_APP_PAY);
                break;
            case WECHAT_SCAN_CODEED_PAY://微信反扫
                domain.setTransactionType(TransactionTypeEnum.DEPOSIT);
                domain.setSubTransactionType(SubTransactionTypeEnum.SCANCODEED_WXPAY);
                break;
            case WECHAT_SCAN_CODE_PAY://微信主扫
                domain.setTransactionType(TransactionTypeEnum.DEPOSIT);
                domain.setSubTransactionType(SubTransactionTypeEnum.SCANCODE_WXPAY);
                break;
            case ALI_APP_PAY://支付宝APP
                domain.setTransactionType(TransactionTypeEnum.DEPOSIT);
                domain.setSubTransactionType(SubTransactionTypeEnum.ALIPAY_APP_PAY);
                break;
            case ALI_SCAN_CODEED_PAY://支付宝反扫
                domain.setTransactionType(TransactionTypeEnum.DEPOSIT);
                domain.setSubTransactionType(SubTransactionTypeEnum.SCANCODEED_ALPPAY);
                break;
            case ALI_SCAN_CODE_PAY://支付宝扫描
                domain.setTransactionType(TransactionTypeEnum.DEPOSIT);
                domain.setSubTransactionType(SubTransactionTypeEnum.SCANCODE_ALPPAY);
                break;
            case SERVICE_WINDOW://支付服务窗
                domain.setTransactionType(TransactionTypeEnum.DEPOSIT);
                domain.setSubTransactionType(SubTransactionTypeEnum.SERVICE_WINDOW);
                break;
                //TODO
            default:

                break;
        }
    }

    /**
     * 工厂方法
     * @param orderBase
     * @return
     */
    protected abstract BaseDomain factory(OrderBase orderBase);

    /**
     * domain某个字段值转换为指定字段值
     * @param domain
     * @param domain
     * @return
     */
    private void annotationToFiled(BaseDomain domain){

        Field[] fields = domain.getClass().getDeclaredFields();
        Set<Field> fieldList = Sets.newHashSet(fields);
        Field[] superFields = domain.getClass().getSuperclass().getDeclaredFields();
        fieldList.addAll(Lists.newArrayList(superFields));

        Map<String,Object> cFiledsMaps = Maps.newHashMap();
        //获取转换注解
        for(Field field :fieldList){
            field.setAccessible(true);
            Field2Filed field2Filed = field.getAnnotation(Field2Filed.class);
            try {
                if(field2Filed != null){
                    String toFiled = field2Filed.toFiled();//属性上面注解值
                    Object pValue = field.get(domain);//属性值
                    if(pValue != null){
                        cFiledsMaps.put(toFiled,pValue);
                    }
                }
            } catch ( Exception e) {
                log.error("GID【{}}】外部流水号【{}】内部流水号【{}】Domain【{}】字段属性转换异常",domain.getGid(),domain.getMerchOrderNo(),domain.getBizOrderNo(),domain,e);
                throw new AbortBizException(e.getMessage());
            }
        }
        //设置值
        if(cFiledsMaps != null && cFiledsMaps.size()>0){
            for(Field field :fieldList){
                field.setAccessible(true);
                if(cFiledsMaps.containsKey(field.getName())){
                    String p = field.getName();
                    try {
                        field.set(domain,cFiledsMaps.get(p));
                    } catch (Exception e) {
                        log.error("GID【{}}】外部流水号【{}】内部流水号【{}】Domain【{}】字段属性转换异常",domain.getGid(),domain.getMerchOrderNo(),domain.getBizOrderNo(),domain,e);
                        throw new AbortBizException(e.getMessage());
                    }
                }
            }
        }
    }
}
